---
description: Компонент для отображения списка действий в виде всплывающего меню.
---

<Overview group="modals">

# ActionSheet [tag:component]

Компонент для отображения списка действий в виде всплывающего меню.
Поддерживает различные режимы отображения в зависимости от платформы и размера экрана. Например,
на платформе iOS компонент имитирует поведение [нативного](https://developer.apple.com/design/human-interface-guidelines/action-sheets/).
В качестве элементов списка принимает коллекцию [`ActionSheetItem`](#action-sheet-item).

</Overview>

<Playground>

```jsx
const [actionSheet, setActionSheet] = React.useState(null);
const targetRef = React.useRef(null);

function handleClose() {
  setActionSheet(null);
}

function handleOpen() {
  setActionSheet(
    <ActionSheet toggleRef={targetRef} onClose={handleClose}>
      <ActionSheetItem>Слушать далее</ActionSheetItem>
      <ActionSheetItem>Поделиться</ActionSheetItem>
      <ActionSheetItem>Скопировать ссылку</ActionSheetItem>
    </ActionSheet>,
  );
}

return (
  <>
    {actionSheet}
    <Button getRootRef={targetRef} onClick={handleOpen} aria-expanded={Boolean(actionSheet)}>
      Туц-туц
    </Button>
  </>
);
```

</Playground>

При использовании данного компонента отталкивайтесь от контекста и количества действий.
Использование `ActionSheet` хорошо подходит для отображения вариантов в ответ на осознанное действие.
Например, при отмене редактирования электронного письма среди доступных вариантов могут быть такие действия как "Удалить изменения",
"Сохранить черновик" и "Вернуть к редактированию".

> По рекомендациям **Apple** следует избегать более четырёх действий в списке (включая действие "Отмена").

> Не используйте компонент для подтверждения действий или предупреждений. Для этого лучше всего подходит компонент `Alert`.

## Обязательные свойства

### `onClose`

Свойство `onClose` принимает функцию, которая вызовется после завершения анимации закрытия компонента.
Обязательно удаляйте из `DOM`-дерева компонент `ActionSheet` в обработчике `onClose`, иначе в верстке останется
прозрачный элемент, который будет мешать дальнейшему взаимодействию с элементами и повторному открытию компонента.

Функция принимает объект с информацией о причине закрытия:

```jsx
function handleClose({ closedBy }) {
  if (closedBy === 'action-item') {
    // закрытие произошло по выбору действия из списка
  } else if (closedBy === 'cancel-item') {
    // закрытие произошло по нажатию на кнопку отмены
  } else if (closedBy === 'cancel-item') {
    // закрытие произошло по другим причинам (например, клик вне области всплывающего окна)
  }
}
```

### `toggleRef` (якорный элемент)

В данное свойство следует передавать элемент, относительно которого будет позиционироваться
компонент в `mode="menu"` (учитывая автоматическое определение режима).
В качестве значения лучше передавать [ref-объект](https://react.dev/learn/manipulating-the-dom-with-refs).

## Режимы отображения

Задаётся свойством `mode`. По умолчанию отображение определяется в зависимости от размеров экрана.

- `"sheet"` — отображение снизу экрана в виде всплывающего окна (по умолчанию для мобильных устройств)
- `"menu"` — отображение в виде всплывающего элемента относительно якорного элемента (по умолчанию для десктопа)

## Шапка

В компоненте есть возможность задать заголовок и описание для списка с помощью свойств `title` и `description` соответственно.

```jsx
<ActionSheet title="Выберите действие" description="Это описание для списка действий">
  <ActionSheetItem>Действие 1</ActionSheetItem>
  <ActionSheetItem>Действие 2</ActionSheetItem>
  <ActionSheetItem>Действие 3</ActionSheetItem>
</ActionSheet>
```

## Позиционирование

### `placement`

Свойство `placement` отвечает за направление положения относительно якорного элемента.
Оно поддерживается только для `mode="menu"` (учитывая автоматическое определение режима).

Обратите внимание, что компонент выбирает наилучшее расположение самостоятельно,
а данное свойство задаёт только _приоритетное_ положение. Это означает, что в случае недостаточного места для позиционирования
по приоритетному положению, будет выбрано любое другое подходящее.

В качестве вариантов положения ориентируйтесь на значения из библиотеки [floating-ui](https://floating-ui.com/docs/tutorial#placements).

### `popupOffsetDistance`

Свойство `popupOffsetDistance` позволяет задать отступ (в пикселях) от якорного элемента.

## Браузерные события

### Click Event

По умолчанию событие `click` не всплывает, что позволяет изолировать компонент от остального приложения.
Если вам необходимо данное событие обрабатывать (например, у вас есть глобальный обработчик клика для сбора аналитики),
воспользуйтесь свойством `allowClickPropagation`.

## Управление фокусом

### `autoFocus`

Данное свойство позволяет автоматически устанавливать фокус на первом интерактивном элементе при открытии всплывающего элемента.
По умолчанию это поведение включено, но можно его отключить, передав `autoFocus={false}`.

Также есть возможность установить фокус на контейнере всплывающего меню, передав `autoFocus="root"`. Это может быть полезно,
когда первый интерактивный элемент имеет подсказку, которая активируется при фокусе. В таком случае появление подсказки сразу
после открытия всплывающего меню может быть нежелательным. Значение `"root"` позволяет поддержать данный сценарий, не ломая доступность.

### `restoreFocus`

Данное свойство позволяет восстанавливать фокус после закрытия всплывающего меню на последний активный элемент.
По умолчанию данное поведение включено, но можно его отключить, передав `restoreFocus={false}`.

Также есть возможность передать в `restoreFocus` функцию, которая возвращает `HTMLElement` или `boolean`.
Если возвращается `HTMLElement`, то фокус будет возвращен на этот элемент, при `false` — фокус не восстанавливается,
при `true` — поведение по умолчанию.

### `timeout`

Свойство позволяет задать задержку (в миллисекундах) при установке и восстановлении фокуса.

## Кнопка "Отмена" [#cancel-item]

Согласно рекомендациям **Apple** в `ActionSheet` должен быть вариант действия "Отмена", который
бы позволял закрывать всплывающее окно без выполнения дополнительных действий.

Используя свойство `iosCloseItem`, можно передать свой вариант элемента "Отмена", по умолчанию
используется компонент `ActionSheetDefaultIosCloseItem`.

> Данное свойство доступно только при выполнении следующих условий:
>
> - платформа iOS
> - `mode="sheet"` (учитывая автоматическое определение режима)

```jsx
import { ActionSheet, ActionSheetDefaultIosCloseItem } from '@vkontakte/vkui';

<ActionSheet
  iosCloseItem={<ActionSheetDefaultIosCloseItem>{cancelLabel}</ActionSheetDefaultIosCloseItem>}
>
  {/* ActionSheetItem */}
  {/* ActionSheetItem */}
  {/* ActionSheetItem */}
</ActionSheet>;
```

## ActionSheetItem [#action-sheet-item]

Подкомпонент для отображения элемента всплывающего меню. Каждому компоненту можно задать различные режимы отображения,
добавлять иконки и метаданные.

<Playground>
  ```jsx
  <ActionSheetItem>Сохранить</ActionSheetItem>
  ```
</Playground>

### Цвет

Задаётся свойством `mode`.

#### `"default"`

Стандартный цвет отображения текста, используется в действиях, где нет необходимости в привлечении дополнительного внимания.

<Playground>
  ```jsx
  <ActionSheetItem>Сохранить</ActionSheetItem>
  ```
</Playground>

#### `"destructive"`

Цвет критических действий (чаще всего красный), старайтесь располагать такие действия сверху списка,
где они наиболее заметны.

<Playground>
  ```jsx
  <ActionSheetItem mode="destructive">Удалить</ActionSheetItem>
  ```
</Playground>

#### `"cancel"`

Цвет действия отмены.

<Playground>
  ```jsx
  <ActionSheetItem mode="cancel">Отмена</ActionSheetItem>
  ```
</Playground>

### Кнопка "Отмена"

Свойство `isCancelItem` позволяет пометить пункт действия как "Отмена".

Согласно рекомендациям **Apple** в `ActionSheet` должен быть вариант действия "Отмена", который
бы позволял закрывать всплывающее окно без выполнения дополнительных действий.

> Обратите внимание, что такой компонент необходимо передавать в свойство `iosCloseItem` у `ActionSheet`,
> потому что данный компонент должен визуально отделяться от остальных пунктов.

Подробнее с использованием можно ознакомиться на странице [`ActionSheet`](/components/action-sheet#cancel-item).

### Текстовые элементы

Основной контент компонента (заголовок) можно задать, передав в свойство `children` необходимый текст:

<Playground>
  ```jsx
  <ActionSheetItem>Скорость воспроизведения</ActionSheetItem>
  ```
</Playground>

Свойство `subtitle` позволяет отобразить дополнительный текст под заголовком:

<Playground>
  ```jsx
  <ActionSheetItem subtitle="Обычная">Скорость воспроизведения</ActionSheetItem>
  ```
</Playground>

Свойство `meta` даёт возможность отобразить небольшой пояснительный текст или индикатор рядом с заголовком:

<Playground>
  ```jsx
  <ActionSheetItem meta={<Icon12Circle fill="var(--vkui--color_icon_negative)" />}>
    Закрепить запись
  </ActionSheetItem>
  ```
</Playground>

#### Многострочный режим

По умолчанию большое количество текста обрезается и заменяется на многоточие, поддерживая однострочный режим отображения.
Это поведение можно отключить (_для всех текстовых элементов_) с помощью свойства `multiline`:

<Playground style={{ maxWidth: 270 }}>
  ```jsx
  <ActionSheetItem multiline>
    Очень длинный заголовок просто для примера, старайтесь избегать такого
  </ActionSheetItem>
  ```
</Playground>

### Контент в начале/в конце

В компоненте доступна возможность добавления дополнительного контента слева и/или справа от текста,
задаётся свойством `before` и `after` соответственно.
Наиболее частый вариант использования свойств `before`/`after` - иконки или аватары.

В соответствии с рекомендациями дизайн-системы, для десктопного представления (`compact`-режим) следует
использовать иконки размером `20px`, для мобильного представления (`regular`-режим) — `28px`.
Проще всего это сделать, используя компонент [`AdaptiveIconRenderer`](/components/adaptive-icon-renderer).

<Playground>
  ```jsx
  <ActionSheetItem
    before={
      <AdaptiveIconRenderer IconCompact={Icon20WriteOutline} IconRegular={Icon28EditOutline} />
    }
  >
    Редактировать профиль
  </ActionSheetItem>
  ```
</Playground>

### Состояния

#### `disabled`

Свойство позволяет отключить возможность взаимодействия с пунктом меню.

<Playground>
  ```jsx
  <ActionSheetItem subtitle="Отсутствуют" disabled>
    Субтитры
  </ActionSheetItem>
  ```
</Playground>

#### `selectable`

Свойство даёт возможность выбирать элемент (визуальная и нативная имитация элемента радиокнопки).
При использовании данного свойства вы также можете передавать стандартные свойства радиокнопок, для управления поведением:

- `name` — имя группы для радиокнопок;
- `value` — значение радиокнопки;
- `defaultChecked` — установить выбранным по умолчанию;
- `checked` и [`onChange`](#onchange) — для контролируемого извне использования выбранного значения;

<Playground direction="column">

```jsx
const [filter, setFilter] = useState('Нормальная');

const onChange = (e) => {
  // e.target.value будет равно значению, переданному в `value` выбранного компонента `ActionSheetItem`
  setFilter(e.target.value);
};

return ['0.25x', '0.5x', '0.75x', 'Нормальная', '1.25x', '1.5x', '2x', '3x'].map((speed) => (
  <ActionSheetItem
    key={speed}
    onChange={onChange}
    checked={filter === speed}
    name="filter"
    value={speed}
    selectable
  >
    {speed}
  </ActionSheetItem>
));
```

</Playground>

Дополнительно через свойство `iconChecked` есть возможность изменить иконки радиокнопки, которая рисуется по умолчанию.

<Playground>
  ```jsx
  <ActionSheetItem
    defaultChecked
    selectable
    iconChecked={
      // квадратные иконки выбора
      <AdaptiveIconRenderer IconCompact={Icon20CheckBoxOn} IconRegular={Icon24CheckBoxOn} />
    }
  >
    0.75x
  </ActionSheetItem>
  ```
</Playground>

### Обработчики событий

#### `onClick`/ `onImmediateClick`

Нажатие на пункт меню можно обработать с помощью свойств `onClick` и `onImmediateClick`.

По умолчанию `onClick` будет вызван после завершения анимации скрытия всплывающего меню и после вызова `onClose`.
Из этого следует, что в объекте события значение поля `currentTarget` будет не определено.
Если вам нужен объект события именно на момент нажатия, воспользуйтесь `onImmediateClick`.

> По умолчанию клик на пункт меню автоматически вызывает закрытие всплывающего меню (функцию, переданную в `onClose` у `ActionSheet`).
>
> Если такое поведение нежелательно, то используйте свойство `autoCloseDisabled`. В таком случае закрытие всплывающего окна
> следует вызывать самостоятельно.

#### `onChange`

Если задано свойство `selectable={true}`, то выбор пункта следует обрабатывать с помощью свойства `onChange`.
Пример можно увидеть [выше](#selectable).

### Ссылки

Если указать свойство `href`, компонент будет рендериться как ссылка `<a>`.
Также можно задать стандартное свойство `target`:

```jsx
<ActionSheetItem href="https://vk.com" target="_blank">
  Перейти на vk.com
</ActionSheetItem>
```

## Доступность (a11y) [#a11y]

- у `ActionSheet` уже заданы атрибуты `role="dialog"` и `aria-modal="true"`, потому что по умолчанию он появляется как диалог и,
  пока он не закроется, нельзя взаимодействовать с другими элементами на странице. Эти атрибуты можно переопределить, явно передавая
  их компоненту;
- у целевого элемента обязательно должен быть выставлен атрибут `aria-expanded`.
- при задании параметра `selectable={true}` для корректной работы важно задать всем `ActionSheetItem` одинаковое значение параметра
  `name`. Обусловлено это тем, что в реализации используется нативный `input[type='radio']` и по пунктам можно навигировать как по
  обычным `radio`-кнопкам;
- при задании `selectable={true}` в реализации используется тег `"label"`. В остальных случаях используется тег `"div"`.

## Свойства и методы [#api]

<PropsTable name={["ActionSheet", "ActionSheetItem"]}>
### ActionSheet [#action-sheet-api]

### ActionSheetItem [#action-sheet-item-api]

</PropsTable>
